package com.xiaoshuidi.cloud.module.contract.api.contract;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils;
import com.xiaoshuidi.cloud.framework.tenant.core.aop.TenantIgnore;
import com.xiaoshuidi.cloud.framework.tenant.core.util.TenantUtils;
import com.xiaoshuidi.cloud.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.xiaoshuidi.cloud.module.contract.api.ContractApi;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.ContractUpdateStatusVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.RoomContractRespVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.contract.vo.customerCompany.CustomerCompanyRespVO;
import com.xiaoshuidi.cloud.module.contract.controller.admin.fee.vo.FeesRespVO;
import com.xiaoshuidi.cloud.module.contract.convert.bill.RentOrderConvert;
import com.xiaoshuidi.cloud.module.contract.convert.contract.ContractConvert;
import com.xiaoshuidi.cloud.module.contract.convert.contract.SettlementDetailConvert;
import com.xiaoshuidi.cloud.module.contract.convert.roommeta.ContractRoommateConvert;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.bill.RentOrderDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.ContractRoomDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.CustomerCompanyDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.SettlementDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.roommeta.ContractRoommateDO;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.bill.RentOrderMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.ContractRoomMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.SettlementDetailMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.SettlementMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.fee.FeesMapper;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.roommeta.ContractRoommateMapper;
import com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.contract.enums.contract.*;
import com.xiaoshuidi.cloud.module.contract.enums.settlement.SettlementStatusEnum;
import com.xiaoshuidi.cloud.module.contract.service.bill.RentOrderService;
import com.xiaoshuidi.cloud.module.contract.service.contract.ContractRoomService;
import com.xiaoshuidi.cloud.module.contract.service.contract.CustomerCompanyService;
import com.xiaoshuidi.cloud.module.contract.service.contract.ContractStayService;
import com.xiaoshuidi.cloud.module.contract.service.roommate.ContractRoommateService;
import com.xiaoshuidi.cloud.module.contract.vo.*;
import com.xiaoshuidi.cloud.module.finance.api.finance.FinanceApi;
import com.xiaoshuidi.cloud.module.finance.api.finance.dto.BankTransferReqDTO;
import com.xiaoshuidi.cloud.module.finance.enums.finance.SourceBizTypeEnum;
import com.xiaoshuidi.cloud.module.iot.common.ResultModel;
import com.xiaoshuidi.cloud.module.member.api.message.MemberMessageApi;
import com.xiaoshuidi.cloud.module.member.api.message.dto.MemberMessageDTO;
import com.xiaoshuidi.cloud.module.rooms.api.reserve.ReserveApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.RoomStateRecordApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.dto.RoomContractInfoDTO;
import com.xiaoshuidi.cloud.module.rooms.api.roomstate.dto.UpdateRoomStateReqDTO;
import com.xiaoshuidi.cloud.module.rooms.api.sdiot.IotRoomDeviceApi;
import com.xiaoshuidi.cloud.module.rooms.enums.RoomContractStatusEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.common.pojo.CommonResult.error;
import static com.xiaoshuidi.cloud.framework.common.pojo.CommonResult.success;

/**
 * OA 合同审批 Service 实现类
 *
 * @author red
 */
@RestController
@Validated
@RequiredArgsConstructor
@Slf4j
public class ContractImplApi implements ContractApi {

    @Resource
    private ContractRoomService contractRoomService;
    @Resource
    private ContractRoomMapper contractRoomMapper;
    @Resource
    private RoomStateRecordApi roomStateRecordApi;
    @Resource
    private SettlementMapper settlementMapper;
    @Resource
    private FinanceApi financeApi;
    @Resource
    private IotRoomDeviceApi iotRoomDeviceApi;
    @Resource
    private MemberMessageApi memberMessageApi;
    @Resource
    private RentOrderMapper rentOrderMapper;
    @Resource
    private RentOrderService rentOrderService;
    @Resource
    private ReserveApi reserveApi;
    @Resource
    private SettlementDetailMapper settlementDetailMapper;
    @Resource
    private ContractRoommateService contractRoommateService;
    @Resource
    private ContractRoommateMapper contractRoommateMapper;
    @Resource
    private ContractStayService contractStayService;
    @Resource
    private CustomerCompanyService customerCompanyService;
    @Resource
    FeesMapper feesMapper;

    /**
     * 审批通过 和审批驳回 修改合同状态
     */
    @Override
    public CommonResult<Long> updateContractStatus(ApproveReqVO reqVO) {
        //查询新合同
        ContractRoomDO contractRoomDO = contractRoomMapper.selectById(reqVO.getId());
        //合同节点
        String contractNode = contractRoomDO.getContractNode();
        ContractUpdateStatusVO updateReqVO = new ContractUpdateStatusVO();
        //修改房态
        UpdateRoomStateReqDTO updateRoomStateReqDTO = new UpdateRoomStateReqDTO();
        updateRoomStateReqDTO.setRoomHouseId(contractRoomDO.getRoomId());
        updateRoomStateReqDTO.setContractInfoDTO(new RoomContractInfoDTO().setExpiryDate(contractRoomDO.getEndTime()).setContractId(contractRoomDO.getId()));
        if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(reqVO.getResult())) {
            try {
                if (ContractNodeEnum.NEW.getCode().equals(contractNode)) {
                    //新签通过
                    setSign(contractRoomDO, updateRoomStateReqDTO);
                    pushServiceEvaluation(contractRoomDO, PushServiceEvaluationTypeEnum.NEW.getMsg(), 1);
                    // 新签消息
                    contractRoomService.sendNewSignSystemEvent(contractRoomDO);
                } else if (ContractNodeEnum.RENEWAL.getCode().equals(contractNode)) {
                    //续租通过
                    setSign(contractRoomDO, updateRoomStateReqDTO);

                    ContractRoomDO contractRoom = contractRoomService.getContractRoom(contractRoomDO.getFromId(), LocalDate.now());
                    log.info("续租审批通过 结束原合同状态：{}", JSONObject.toJSONString(contractRoom));
                    if (contractRoom != null && contractRoom.getEndTime().isBefore(LocalDate.now())) {
                        if (ContractSignStatusEnum.SIGNED.getCode().equals(contractRoomDO.getSignStatus())){
                            //更改续租合同状态为原合同状态
                            contractRoomDO.setContractStatus(contractRoom.getContractStatus());
                        }else {
                            contractRoomDO.setContractStatus(ContractStatusEnum.NO_SIGNED.getCode());
                        }
                        contractRoomMapper.updateById(contractRoomDO);
                        //修改原合同状态
                        contractRoom.setOldContractNode(contractRoom.getContractNode());
                        contractRoom.setContractNode(ContractNodeEnum.RENTING_OUT.getCode());
                        contractRoom.setContractStatus(ContractStatusEnum.NORMAL_END.getCode());
                        contractRoom.setActualEndTime(contractRoomDO.getStartTime());
                        contractRoomMapper.updateById(contractRoom);
                        //把原合同的主住人、同住人迁过来
                        contractRoommateService.roommateTransfer(contractRoomDO.getFromId(), contractRoomDO.getId(), contractRoom.getRoomId());
//                        contractRoomService.updateRoomStatus(contractRoomDO.getRoomId(), contractRoom.getContractNode(), false, contractRoom.getContractStatus(),
//                                contractRoom.getCustomerName(), contractRoom.getCustomerPhone(), contractRoom.getId(), contractRoomDO.getEndTime());
                        //迁移交房数据
                        contractStayService.migrateStayData(Collections.singletonList(contractRoomDO.getId()));
                    }
                    //推送通知
                    pushServiceEvaluation(contractRoomDO, PushServiceEvaluationTypeEnum.RENEWAL.getMsg(),
                            PushServiceEvaluationTypeEnum.RENEWAL.getCode());
                } else if (ContractNodeEnum.EXCHANGE.getCode().equals(contractNode)) {
                    //换房通过
                    setSign(contractRoomDO, updateRoomStateReqDTO);
                    //换房通过 结束原合同
                    ContractRoomDO oldContractRoomDO = contractRoomMapper.selectById(contractRoomDO.getFromId());
                    log.info("换房审批通过 结束原合同状态：{}", JSONObject.toJSONString(oldContractRoomDO));
                    if (oldContractRoomDO != null) {
                        oldContractRoomDO.setContractNode(ContractNodeEnum.RENTING_OUT.getCode());
                        oldContractRoomDO.setContractStatus(ContractStatusEnum.ABNORMAL_END.getCode());
                        oldContractRoomDO.setActualEndTime(contractRoomDO.getStartTime());
                        contractRoomMapper.updateById(oldContractRoomDO);
                    }
                }
                if (ContractNodeEnum.NEW.getCode().equals(contractNode) || ContractNodeEnum.EXCHANGE.getCode().equals(contractNode)) {
                    log.info("合同审批通过=====:{}", JSONObject.toJSONString(contractRoomDO));
                    log.info("审批通过新合同的房态修改:{}", JSON.toJSONString(updateRoomStateReqDTO));
                    CommonResult<Boolean> commonResult = roomStateRecordApi.updateRoomStateByContract(updateRoomStateReqDTO);
                    log.info("新合同修改房态返回：{}", commonResult.getData());
                    //发送 预定信息
                    log.error("预定信息：{},memberId：{}", contractRoomDO.getRoomId(), contractRoomDO.getMemberId());
                    CommonResult<Boolean> booleanCommonResult = reserveApi.signSuccess(contractRoomDO.getRoomId(), contractRoomDO.getMemberId());
                    log.info("预定返回：{}", booleanCommonResult.getData());
                }
            } catch (Exception e) {
                log.error("不需要审批，参数roomId：{}，memberId：{}，异常信息：{}", contractRoomDO.getRoomId(), contractRoomDO.getMemberId(), e);
            }
        }
        if (BpmProcessInstanceResultEnum.REJECT.getResult().equals(reqVO.getResult())) {
            log.info("合同审批驳回:{}====:{}", JSONObject.toJSONString(contractRoomDO), JSONObject.toJSONString(updateRoomStateReqDTO));
            if (ContractNodeEnum.NEW.getCode().equals(contractNode)) {
                //新签驳回
                updateRoomStateReqDTO.setRoomContractStatusEnum(RoomContractStatusEnum.REJECT);
                reqVO.setContractStatus(ContractStatusEnum.ABNORMAL_END.getCode());
                contractRoomDO.setContractStatus(ContractStatusEnum.REJECT.getCode());
            } else if (ContractNodeEnum.RENEWAL.getCode().equals(contractNode)) {
                //续租驳回
                updateRoomStateReqDTO.setRoomContractStatusEnum(RoomContractStatusEnum.REJECT);
                reqVO.setContractStatus(ContractStatusEnum.ABNORMAL_END.getCode());
                contractRoomDO.setContractStatus(ContractStatusEnum.REJECT.getCode());
            } else if (ContractNodeEnum.EXCHANGE.getCode().equals(contractNode)) {
                //换房驳回
                updateRoomStateReqDTO.setRoomContractStatusEnum(RoomContractStatusEnum.REJECT);
                reqVO.setContractStatus(ContractStatusEnum.ABNORMAL_END.getCode());
                contractRoomDO.setContractStatus(ContractStatusEnum.REJECT.getCode());
            }
            log.info("setSign:{},{}", contractRoomDO.getContractStatus(), contractRoomDO.getSignStatus());
            log.info("审批驳回 新合同的房态修改:{}", JSON.toJSONString(updateRoomStateReqDTO));
            CommonResult<Boolean> commonResult = roomStateRecordApi.updateRoomStateByContract(updateRoomStateReqDTO);
            log.info("新合同修改房态返回：{}", commonResult.getData());
        }
        //修改 新合同状态
        updateReqVO.setId(contractRoomDO.getId());
        updateReqVO.setContractStatus(contractRoomDO.getContractStatus());
        updateReqVO.setSignStatus(contractRoomDO.getSignStatus());
        updateReqVO.setChangeEffectiveTime(contractRoomDO.getChangeEffectiveTime());
        contractRoomService.update(updateReqVO);
        return success();
    }

    /**
     * 审批通过 新合同状态 房态变化
     */
    private void setSign(ContractRoomDO contractRoomDO, UpdateRoomStateReqDTO updateRoomStateReqDTO) {
        if (ContractSignStatusEnum.SIGNED.getCode().equals(contractRoomDO.getSignStatus())) {
            updateRoomStateReqDTO.setRoomContractStatusEnum(RoomContractStatusEnum.ACTIVE);
            contractRoomDO.setContractStatus(ContractStatusEnum.ACTIVE.getCode());
            contractRoomDO.setChangeEffectiveTime(LocalDateTime.now());
        } else {
            updateRoomStateReqDTO.setRoomContractStatusEnum(RoomContractStatusEnum.NO_SIGNED);
            contractRoomDO.setContractStatus(ContractStatusEnum.NO_SIGNED.getCode());
        }
    }

    /**
     * 只返回已入驻的合同memberid
     *
     * @param roomId
     * @return
     */
    @Override
    public CommonResult<CustomerVO> getContractMemberIdByRoomId(Long roomId) {
        List<ContractRoomDO> contracts = TenantUtils.executeIgnoreAndReturn(() -> contractRoomService.getContractByRoomId(roomId));
        return success(contracts.stream().filter(c ->
                        (ContractStatusEnum.CHECK_IN.getCode().equals(c.getContractStatus()))
                                && c.getStartTime().compareTo(LocalDate.now()) <= 0)
                .findFirst().map(c -> {
                    CustomerVO kv = new CustomerVO();
                    if (CustomerTypeEnum.PERSONAL.getCode().equals(c.getCustomerType())
                            || Objects.equals(CompanyContractOrderShareTypeEnum.RENT_DEPOSIT_ONLY_WITH_PERSONAL.getCode(), c.getOrderShareMethod())) {
                        kv.setId(c.getMemberId());
                        kv.setType(CustomerTypeEnum.PERSONAL.getCode());
                    } else if (CustomerTypeEnum.COMPANY.getCode().equals(c.getCustomerType())
                            && Objects.equals(CompanyContractOrderShareTypeEnum.RENT_DEPOSIT_ONLY_WITH_ROOM.getCode(), c.getOrderShareMethod())) {
                        kv.setId(c.getMemberId());
                        kv.setType("room");
                        kv.setStartTime(c.getStartTime().format(DateTimeFormatter.ISO_DATE));
                        kv.setCompanyId(c.getCustomerCompanyId());
                        kv.setCompanyName(c.getCustomerName());
                    } else {
                        kv.setId(c.getCustomerCompanyId());
                        kv.setType(CustomerTypeEnum.COMPANY.getCode());
                    }
                    kv.setRoomId(c.getRoomId());
                    kv.setApartmentName(c.getApartmentName());
                    kv.setApartmentId(c.getApartmentId());
                    kv.setRoomName(c.getRoomName());
                    kv.setTenantId(c.getTenantId());
                    return kv;
                }).orElse(null));
    }

    @Override
    public CommonResult<RenterVO> getContractRenterInfoByRoomId(Long roomId) {
        return TenantUtils.executeIgnoreAndReturn(() -> {
            List<ContractRoomDO> contracts = contractRoomService.getContractByRoomId(roomId);
            RenterVO vo = contracts.stream().filter(c ->
                            (ContractStatusEnum.ACTIVE.getCode().equals(c.getContractStatus()) || ContractStatusEnum.CHECK_IN.getCode().equals(c.getContractStatus()))
                                    && !c.getStartTime().isAfter(LocalDate.now()) && !c.getEndTime().isBefore(LocalDate.now()))
                    .findFirst().map(c -> {
                        RenterVO a = new RenterVO().setCustomerName(c.getCustomerName())
                                .setContractId(c.getId())
                                .setContractNo(c.getContractNo())
                                .setStartTime(c.getStartTime())
                                .setEndTime(c.getEndTime())
                                .setCustomerType(c.getCustomerType())
                                .setCustomerPhone(c.getCustomerPhone())
                                .setTenantId(c.getTenantId())
                                .setMemberId(c.getMemberId());
                        if (CustomerTypeEnum.COMPANY.name().equals(c.getCustomerType())) {
                            List<ContractRoommateDO> l = contractRoommateMapper.selectRoommateListByContractId(c.getId());
                            ContractRoommateDO roommateDO = l.stream().filter(m -> "2".equals(m.getStatus())).findFirst().orElse(null);
                            if (roommateDO != null) {
                                a.setCustomerPhone(roommateDO.getRoommatePhone());
                                a.setMemberId(roommateDO.getMemberId());
                            }
                        }
                        return a;
                    }).orElse(null);
            return vo != null ? success(vo) : error(ErrorCodeConstants.CONTRACT_NOT_EXISTS);
        });
    }

    @Override
    public CommonResult<RenterVO1> getContractRenterListByRoomId(Long roomId) {
        return TenantUtils.executeIgnoreAndReturn(() -> {
            List<ContractRoomDO> contracts = contractRoomService.getContractByRoomId(roomId);
            RenterVO1 vo = contracts.stream().filter(c ->
                            (ContractStatusEnum.ACTIVE.getCode().equals(c.getContractStatus()) || ContractStatusEnum.CHECK_IN.getCode().equals(c.getContractStatus()))
                                    && !c.getStartTime().isAfter(LocalDate.now()) && !c.getEndTime().isBefore(LocalDate.now()))
                    .findFirst().map(c -> {
                        RenterVO1 a = new RenterVO1()
                                .setContractId(c.getId())
                                .setContractNo(c.getContractNo())
                                .setStartTime(c.getStartTime())
                                .setEndTime(c.getEndTime())
                                .setCustomerType(c.getCustomerType())
                                .setRenter(c.getCustomerName())
                                .setRenterPhone(c.getCustomerPhone())
                                .setOrderShareMethod(c.getOrderShareMethod())
                                .setTenantId(c.getTenantId());

                        if(CustomerTypeEnum.PERSONAL.getCode().equals(c.getCustomerType())||
                            (CustomerTypeEnum.COMPANY.getCode().equals(c.getCustomerType()) &&
                                    CompanyContractOrderShareTypeEnum.ALL.getCode().equals(c.getOrderShareMethod()))){
                            //个人和企业承担所有都只发合同上的承租人
                            CustomerInfoVO customerInfoVO = new CustomerInfoVO()
                                    .setCustomerName(c.getCustomerName())
                                    .setCustomerPhone(c.getCustomerPhone())
                                    .setMemberId(c.getMemberId());
                            a.setCustmerInfoList(Arrays.asList(customerInfoVO));
                        }
                        if (CustomerTypeEnum.COMPANY.getCode().equals(c.getCustomerType())) {
                            List<ContractRoommateDO> l = contractRoommateMapper.selectRoommateListByContractId(c.getId());
                            l = l.stream().filter(m -> "2".equals(m.getStatus())).collect(Collectors.toList());
                            if(CompanyContractOrderShareTypeEnum.RENT_DEPOSIT_ONLY_WITH_PERSONAL.getCode().equals(c.getOrderShareMethod())){
                                //企业承担租金押金，发给寝室长
                                ContractRoommateDO roommateDO = l.stream().filter(m->m.getRoommateType()==1).findFirst().orElse(null);
                                if (roommateDO != null) {
                                    CustomerInfoVO customerInfoVO = new CustomerInfoVO()
                                            .setCustomerName(roommateDO.getRoommateName())
                                            .setCustomerPhone(roommateDO.getRoommatePhone())
                                            .setMemberId(roommateDO.getMemberId());
                                    a.setCustmerInfoList(Arrays.asList(customerInfoVO));
                                }
                            }else if(CompanyContractOrderShareTypeEnum.RENT_DEPOSIT_ONLY_WITH_ROOM.getCode().equals(c.getOrderShareMethod())){
                                ArrayList<CustomerInfoVO> customerInfoVOS = new ArrayList<>();
                                //企业是房屋钱包模式，都发
                                for (ContractRoommateDO roommateDO : l) {
                                    CustomerInfoVO customerInfoVO = new CustomerInfoVO()
                                            .setCustomerName(roommateDO.getRoommateName())
                                            .setCustomerPhone(roommateDO.getRoommatePhone())
                                            .setMemberId(roommateDO.getMemberId());
                                    customerInfoVOS.add(customerInfoVO);
                                }
                                a.setCustmerInfoList(customerInfoVOS);
                            }
                        }
                        return a;
                    }).orElse(null);
            return vo != null ? success(vo) : error(ErrorCodeConstants.CONTRACT_NOT_EXISTS);
        });
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getRoomIdByUserId() {
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        return getRoomIdByUserId(loginUserId);
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getRoomIdByUserId(Long memberId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractRoomDO::getMemberId, memberId)
                .and(qe -> qe.in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.ACTIVE.getCode(),
                                ContractStatusEnum.CHECK_IN.getCode()))
                        .or(item -> item.eq(ContractRoomDO::getContractStatus, ContractStatusEnum.REJECT.getCode())
                                .in(ContractRoomDO::getContractNode, Arrays.asList(
                                        ContractNodeEnum.RENEWAL.getCode(),
                                        ContractNodeEnum.RENTING_OUT.getCode(),
                                        ContractNodeEnum.EXCHANGE.getCode())))
                )
                .orderByDesc(ContractRoomDO::getSignedTime)
        ;
        List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractRoomDOS)) {
            return success(ContractConvert.INSTANCE.convertList07(contractRoomDOS));
        }
        return success(new ArrayList<>(0));
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getRoomIdByCompanyId(Long companyId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.and(qe -> qe.eq(ContractRoomDO::getCustomerCompanyId, companyId)
                        .in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.ACTIVE.getCode(),
                                ContractStatusEnum.CHECK_IN.getCode())))
                .or(qe -> qe.eq(ContractRoomDO::getContractStatus, ContractStatusEnum.REJECT.getCode())
                        .in(ContractRoomDO::getContractNode, Arrays.asList(ContractNodeEnum.RENEWAL.getCode(),
                                ContractNodeEnum.RENTING_OUT.getCode(),
                                ContractNodeEnum.EXCHANGE.getCode())))
                .orderByDesc(ContractRoomDO::getSignedTime)
        ;
        List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractRoomDOS)) {
            return success(ContractConvert.INSTANCE.convertList07(contractRoomDOS));
        }
        return success(new ArrayList<>(0));
    }


    @Override
    public CommonResult<List<ContractRoomRespVO>> getContractPhone(String phone, List<String> contractStatus) {
        List<ContractRoomRespVO> contractPhone = contractRoomService.getContractPhone(phone, contractStatus);
        return success(contractPhone);
    }

    private void createBankTransfer(ContractRoomDO contract, SettlementDO settlementDO) {
        BankTransferReqDTO bankTransferReqDTO = new BankTransferReqDTO();
        bankTransferReqDTO
                .setOperator(contract.getSignerName());
        bankTransferReqDTO.setBizDate(LocalDate.now());
        bankTransferReqDTO.setBizNo(settlementDO.getId().toString());
        bankTransferReqDTO.setBizType(SourceBizTypeEnum.SETTLEMENT_BILL.name());
        bankTransferReqDTO.setContractNo(contract.getContractNo());
        bankTransferReqDTO.setPayeeName(StringUtils.isNotBlank(settlementDO.getCardholder()) ? settlementDO.getCardholder()
                : contract.getCustomerName());
        bankTransferReqDTO.setPayeeType("租客");
        bankTransferReqDTO.setPayeeMobile(contract.getCustomerPhone());
        bankTransferReqDTO.setPayAmount(settlementDO.getAmount());
        bankTransferReqDTO.setPayeeBank(settlementDO.getCustomerBank());
        bankTransferReqDTO.setPayeeBankBranch(settlementDO.getCustomerBankArea());
        bankTransferReqDTO.setPayeeBankCode(settlementDO.getBankCode());
        bankTransferReqDTO.setPayeeBankCity(settlementDO.getBankCity());
        bankTransferReqDTO.setPayeeBankProvince(settlementDO.getBankProvince());
        bankTransferReqDTO.setPayeeBankAccount(settlementDO.getCustomerCreditCard());
        bankTransferReqDTO.setReason(settlementDO.getEvictionReason());
        bankTransferReqDTO.setAttachment(settlementDO.getCertificateUrl());
        bankTransferReqDTO.setTenantId(contract.getTenantId());
        bankTransferReqDTO.setDeptId(contract.getDeptId());

        CommonResult<Void> result = financeApi.bankTransfer(bankTransferReqDTO);
        result.checkError();
    }

    /**
     * 退租审批业务处理
     */
    public CommonResult<Long> updateRentingOutContractStatus(ApproveReqVO reqVO) {
        log.info("退租合同:{}", JSON.toJSONString(reqVO));
        //查询新合同
        ContractRoomDO contractRoomDO = contractRoomMapper.selectById(reqVO.getId());
        //修改房态
        UpdateRoomStateReqDTO updateRoomStateReqDTO = new UpdateRoomStateReqDTO();
        updateRoomStateReqDTO.setRoomHouseId(contractRoomDO.getRoomId());
        updateRoomStateReqDTO.setContractInfoDTO(new RoomContractInfoDTO().setExpiryDate(contractRoomDO.getEndTime()).setContractId(contractRoomDO.getId()));

        //退租 修改 合同状态
        ContractUpdateStatusVO updateReqVO = new ContractUpdateStatusVO();
        updateReqVO.setId(contractRoomDO.getId());
        SettlementDO settlementDO = settlementMapper.selectOne(new QueryWrapper<SettlementDO>().eq("contract_id", contractRoomDO.getId())
                .orderByDesc("id")
                .last("limit 1"));
        if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(reqVO.getResult())) {

            if (EvictionTypeEnum.NORMAL_RENTING.getCode().equals(contractRoomDO.getEvictionType())) {
                updateRoomStateReqDTO.setRoomContractStatusEnum(RoomContractStatusEnum.NORMAL_END);
                contractRoomDO.setContractStatus(ContractStatusEnum.NORMAL_END.getCode());
                updateReqVO.setContractStatus(ContractStatusEnum.NORMAL_END.getCode());
            } else {
                updateRoomStateReqDTO.setRoomContractStatusEnum(RoomContractStatusEnum.ABNORMAL_END);
                contractRoomDO.setContractStatus(ContractStatusEnum.ABNORMAL_END.getCode());
                updateReqVO.setContractStatus(ContractStatusEnum.ABNORMAL_END.getCode());
            }
            updateReqVO.setActualEndTime(settlementDO.getEvictionTime());
            log.info("退租确认：{}", JSONObject.toJSONString(updateReqVO));
            contractRoomService.update(updateReqVO);

            // 续租/换房合同
            ContractRoomDO renewContract = contractRoomService.getByFromId(contractRoomDO.getId());
            if (renewContract != null) {
                log.info("退租确认, 修改续租合同 {}", renewContract.getId());
                ContractRoomDO updateDO = new ContractRoomDO();
                updateDO.setId(renewContract.getId());
                updateDO.setContractNode(ContractNodeEnum.RENTING_OUT.getCode());
                updateDO.setContractStatus(updateReqVO.getContractStatus());
                updateDO.setActualEndTime(settlementDO.getEvictionTime());
                contractRoomMapper.updateById(updateDO);
            }

            log.info("退租---房态修改:{}", JSON.toJSONString(updateRoomStateReqDTO));
            CommonResult<Boolean> commonResult = roomStateRecordApi.updateRoomStateByContract(updateRoomStateReqDTO);
            log.info("退租---修改房态返回：{}", commonResult.getData());
            settlementDO.setClearedStatus(SettlementStatusEnum.HAVE_TAKEN_EFFECT.getCode());
            settlementMapper.updateById(settlementDO);
            //修改合同未支付账单为取消
            rentOrderMapper.updatePayStatusCancel(contractRoomDO.getId());
            
            //红冲
            contractRoomService.redInvocie(settlementDO.getEvictionTime(), Collections.singletonList(reqVO.getId()));
            
            // 退租收费
            contractRoomService.createCheckoutSettlementRentOrder(contractRoomDO, settlementDO,
                    SettlementDetailConvert.INSTANCE.convert2(settlementDetailMapper.selectList("settlement_id", settlementDO.getId())));
            //删除下发密码
            List<String> mobiles = contractRoommateMapper.selectByContractId(contractRoomDO.getId());
            ResultModel resultModel = iotRoomDeviceApi.clearPassword1(contractRoomDO.getRoomId(), mobiles);
            log.info("删除房间密码:{} resp:{}", contractRoomDO.getRoomId(), JSONObject.toJSONString(resultModel));
            try {
                pushServiceEvaluation(contractRoomDO, PushServiceEvaluationTypeEnum.RENTING_OUT.getMsg(),
                        PushServiceEvaluationTypeEnum.RENTING_OUT.getCode());
            } catch (Exception e) {
                log.error("", e);
            }
        }
        if (BpmProcessInstanceResultEnum.REJECT.getResult().equals(reqVO.getResult())) {
            //退租驳回
            contractRoomDO.setContractNode(contractRoomDO.getOldContractNode());
            contractRoomDO.setContractStatus(contractRoomDO.getOldContractStatus());
            log.info("setSign:{},{}", contractRoomDO.getContractStatus(), contractRoomDO.getSignStatus());
            updateReqVO.setContractStatus(contractRoomDO.getOldContractStatus());
            updateReqVO.setContractNode(contractRoomDO.getOldContractNode());
            log.info("退租驳回确认：{}", JSONObject.toJSONString(updateReqVO));
            contractRoomService.update(updateReqVO);
            //设置 结算单 为已驳回
            settlementDO.setClearedStatus(SettlementStatusEnum.REJECT.getCode());
            /*Long id = settlementDO.getId();
            settlementMapper.deleteById(id);
            log.info("settlementDO:{}", id);
            LambdaQueryWrapper<SettlementDetailDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(SettlementDetailDO::getId, id);
            settlementDetailMapper.delete(lambdaQueryWrapper);*/
            settlementMapper.updateById(settlementDO);
            log.info("退租驳回---房态修改:{}", JSON.toJSONString(updateRoomStateReqDTO));
            CommonResult<Boolean> commonResult = roomStateRecordApi.updateRoomStateByContract(updateRoomStateReqDTO);
            log.info("退租驳回---修改房态返回：{}", commonResult.getData());
        }

        return success();
    }

    @Override
    public CommonResult<ContractRoomReqVO> getRoomIdByApartment(Long memberId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.and(qe -> qe.eq(ContractRoomDO::getMemberId, memberId)
                        .in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.ACTIVE.getCode(),
                                ContractStatusEnum.CHECK_IN.getCode())))
                .or(qe -> qe.eq(ContractRoomDO::getContractStatus, ContractStatusEnum.REJECT.getCode())
                        .in(ContractRoomDO::getContractNode, Arrays.asList(ContractNodeEnum.RENEWAL.getCode(),
                                ContractNodeEnum.RENTING_OUT.getCode(),
                                ContractNodeEnum.EXCHANGE.getCode())))
                .orderByDesc(ContractRoomDO::getCreateTime)
        ;
        List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractRoomDOS)) {
            return success(ContractConvert.INSTANCE.convert3(contractRoomDOS.get(0)));
        }
        return success(null);
    }

    private void pushServiceEvaluation(ContractRoomDO contractRoomDO, String content, Integer commentType) {
        MemberMessageDTO memberMessageDTO = new MemberMessageDTO();
        if (contractRoomDO != null) {
            memberMessageDTO.setUserId(contractRoomDO.getMemberId());
            memberMessageDTO.setContent(content);
            memberMessageDTO.setType(1);
            memberMessageDTO.setStatus(1);
            memberMessageDTO.setDestination(3);
            memberMessageDTO.setCreator(contractRoomDO.getCreator());

            memberMessageDTO.setSteward(contractRoomDO.getSignerName());
            memberMessageDTO.setStewardId(contractRoomDO.getSignerId());

            memberMessageDTO.setCommentType(commentType);
            memberMessageDTO.setApartmentName(contractRoomDO.getApartmentName());
            memberMessageDTO.setRoomId(contractRoomDO.getRoomId());
            memberMessageDTO.setSignDay(contractRoomDO.getSignedTime());
            memberMessageApi.create(memberMessageDTO);
        }
    }

    @Override
    @TenantIgnore
    public CommonResult<List<RentOrderVO>> getOverdueUnpaidOrder() {
        QueryWrapper<ContractRoomDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(ContractRoomDO::getCustomerType, CustomerTypeEnum.PERSONAL.getCode());
        //合同状态在（状态是非结束状态非失效，不是续租）or（状态是非结束状态非失效，不是审批状态，是续租，在周期内）
        LocalDate now = LocalDate.now();
        queryWrapper.lambda()
                .and(qw ->
                        qw.and(qw2 -> qw2.notIn(ContractRoomDO::getContractStatus,
                                                Arrays.asList(ContractStatusEnum.NORMAL_END.getCode(),
                                                        ContractStatusEnum.ABNORMAL_END.getCode(),
                                                        ContractStatusEnum.LOST_EFFECTIVENESS.getCode()))
                                        .ne(ContractRoomDO::getContractNode, ContractNodeEnum.RENEWAL.getCode()))
                                .or(qw1 -> qw1.le(ContractRoomDO::getStartTime, now).ge(ContractRoomDO::getEndTime, now)
                                        .eq(ContractRoomDO::getContractNode, ContractNodeEnum.RENEWAL.getCode())
                                        .notIn(ContractRoomDO::getContractStatus,
                                                Arrays.asList(ContractStatusEnum.NORMAL_END.getCode(),
                                                        ContractStatusEnum.ABNORMAL_END.getCode(),
                                                        ContractStatusEnum.LOST_EFFECTIVENESS.getCode(),
                                                        ContractStatusEnum.PENDING.getCode()))));
        List<ContractRoomDO> contractDO = contractRoomMapper.selectList(queryWrapper);
        //查询  过期未支付的账单
        List<Long> contractList = contractDO.stream().map(ContractRoomDO::getId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(contractList)) {
            List<RentOrderDO> rentOrderDOList = rentOrderService.overdueUnpaidOrder(contractList);
            List<RentOrderVO> rentOrderRespVOS = RentOrderConvert.INSTANCE.convertList04(rentOrderDOList);
            return success(rentOrderRespVOS);
        }
        return success(null);
    }


    @Override
    public CommonResult<List<ContractRoommateApiVO>> getRoommateByRoomId(Long roomId) {
        log.info("房间ID获取同住人信息，请求参数：{}", roomId);
        if (Objects.isNull(roomId)) {
            return success(null);
        }
        RoomContractRespVO roomContract = contractRoomService.getRoomContract(roomId);
        if (Objects.isNull(roomContract)) {
            return success(null);
        }

        ContractRoommateDO param = new ContractRoommateDO();
        param.setRoomId(roomId);
        param.setStatus(RoommateStatusEnum.CHECKED_ID.getCode().toString());
        param.setRoomContractId(roomContract.getId());
        List<ContractRoommateDO> byParam = contractRoommateService.getByParam(param);
        List<ContractRoommateApiVO> contractRoommateApiVOS = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(byParam)) {
            contractRoommateApiVOS = ContractRoommateConvert.INSTANCE.convertList2Api(byParam);
        }
        // 企业合同
        if (CustomerTypeEnum.COMPANY.getCode().equals(roomContract.getCustomerType()) && Objects.nonNull(roomContract.getCustomerCompanyId())){
            CustomerCompanyDO companyDoById = customerCompanyService.getCompanyDoById(roomContract.getCustomerCompanyId());
            if (Objects.nonNull(companyDoById)){
                if (CollectionUtils.isEmpty(contractRoommateApiVOS)){
                    ContractRoommateApiVO roommateApiVO = new ContractRoommateApiVO();
                    roommateApiVO.setRoomContractId(roomContract.getId());
                    roommateApiVO.setRoomId(roomContract.getRoomId());
                    roommateApiVO.setRoommateType(RoommateTypeEnum.LESSESS.getCode());
                    roommateApiVO.setContractCustomerType(CustomerTypeEnum.COMPANY.getCode());
                    roommateApiVO.setCompanyId(companyDoById.getId());
                    roommateApiVO.setCompanyName(companyDoById.getCompanyName());
                    contractRoommateApiVOS.add(roommateApiVO);
                }else {
                    contractRoommateApiVOS.forEach(r -> {r.setCompanyId(companyDoById.getId()); r.setCompanyName(companyDoById.getCompanyName());});
                }
            }
        }
        return success(contractRoommateApiVOS);
    }

    @Override
    public CommonResult<List<Long>> getMemberIdsByApartmentId(Long apartmentId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.ACTIVE.getCode(),
                ContractStatusEnum.ABNORMAL_END.getCode()));
        List<ContractRoomDO> contractDO = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(contractDO)) {
            return CommonResult.success();
        }
        List<Long> contractIds = contractDO.stream().map(ContractRoomDO::getId).distinct().collect(Collectors.toList());
        List<Long> memberIds = contractRoommateService.getContractRoommateList(contractIds);
        return CommonResult.success(memberIds);
    }

    @Override
    public CommonResult<List<Long>> getMemberIdsByApartmentIds(List<Long> apartmentIds) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.ACTIVE.getCode(),
                        ContractStatusEnum.CHECK_IN.getCode()))
                .in(ContractRoomDO::getApartmentId, apartmentIds);
        List<ContractRoomDO> contractDOs = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(contractDOs)) {
            return CommonResult.success();
        }
        List<Long> contractIds =
                contractDOs.stream().map(ContractRoomDO::getId).distinct().collect(Collectors.toList());
        List<Long> memberIds = contractRoommateService.getContractRoommateList(contractIds);
        return CommonResult.success(memberIds);
    }


    @Override
    public CommonResult<RoomContractApiRespVO> getContractByRoomId(Long roomId) {
        if (Objects.isNull(roomId)) {
            return CommonResult.success(null);
        }
        RoomContractRespVO roomContract = contractRoomService.getRoomContract(roomId);
        return CommonResult.success(ContractConvert.INSTANCE.convertResp2ApiResp(roomContract));
    }

    @Override
    public CommonResult<List<RoomContractApiRespVO>> getContractByRoomIds(List<Long> roomIds) {
        List<ContractRoomDO> l = contractRoomService.getContractByRoomIds(roomIds);
        return CommonResult.success(ContractConvert.INSTANCE.convertList08(l.stream()
                .filter(c -> ContractStatusEnum.ACTIVE.getCode().equals(c.getContractStatus())
                || ContractStatusEnum.CHECK_IN.getCode().equals(c.getContractStatus())
                || ContractStatusEnum.NORMAL_END.getCode().equals(c.getContractStatus())
                || ContractStatusEnum.ABNORMAL_END.getCode().equals(c.getContractStatus()))
                .collect(Collectors.toList())));
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getAllContractByUserId(Long memberId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractRoomDO::getMemberId, memberId)
                .orderByDesc(ContractRoomDO::getSignedTime)
        ;
        List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractRoomDOS)) {
            return success(ContractConvert.INSTANCE.convertList07(contractRoomDOS));
        }
        return success(new ArrayList<>(0));
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getAllContractByRoomMateUserId(Long memberId) {
        return success(contractRoomMapper.getAllContractByRoomMateUserId(memberId));
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getAllContractByCompanyId(Long companyId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractRoomDO::getCustomerCompanyId, companyId)
                .orderByDesc(ContractRoomDO::getSignedTime);
        List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractRoomDOS)) {
            return success(ContractConvert.INSTANCE.convertList07(contractRoomDOS));
        }
        return success(new ArrayList<>(0));
    }

    /**
     * 企业id和房源id获取合同信息
     *
     * @param companyId
     * @param roomId
     * @return
     */
    @Override
    public CommonResult<List<ContractRoomReqVO>> getAllContractByCompanyIdAndRoomId(Long companyId, Long roomId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(ContractRoomDO::getCustomerCompanyId, companyId)
                .eq(ContractRoomDO::getRoomId, roomId)
                .orderByDesc(ContractRoomDO::getSignedTime);
        List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractRoomDOS)) {
            return success(ContractConvert.INSTANCE.convertList07(contractRoomDOS));
        }
        return success(new ArrayList<>(0));
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getRoomDataIdByUserId(Long memberId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(ContractRoomDO::getMemberId, memberId)
                .isNull(ObjectUtil.isNull(memberId), ContractRoomDO::getId)
                .in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.CHECK_IN.getCode(),
                        ContractStatusEnum.ACTIVE.getCode()))
                .orderByAsc(ContractRoomDO::getStartTime);
        List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(contractRoomDOS)) {
            Map<Long, List<ContractRoomDO>> collect = contractRoomDOS.stream().collect(Collectors.groupingBy(ContractRoomDO::getRoomId));
            List<ContractRoomDO> collect1 = collect.values().stream().map(m -> m.get(0)).collect(Collectors.toList());
            return success(ContractConvert.INSTANCE.convertList07(collect1));
        }
        return success(new ArrayList<>(0));
    }

    @Override
    public CommonResult<RoomContractApiRespVO> getRenewalContractByContractId(Long contractId) {
        ContractRoomDO contractRoomDO = contractRoomService.get(contractId);
        ContractRoomDO renewalContractRoomDO = getEndRenewalContract(contractRoomDO);
        return success(ContractConvert.INSTANCE.convertRoomDo2ApiResp(renewalContractRoomDO));
    }

    private ContractRoomDO getEndRenewalContract(ContractRoomDO contractRoomDO) {
        if (Objects.isNull(contractRoomDO)) {
            return null;
        }
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ContractRoomDO::getFromId, contractRoomDO.getId());
        queryWrapper.in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.ACTIVE.getCode(), ContractStatusEnum.CHECK_IN.getCode()));
        queryWrapper.orderByDesc(ContractRoomDO::getCreateTime);
        List<ContractRoomDO> list = contractRoomMapper.selectList(queryWrapper);
        ContractRoomDO renewalContract = null;
        if (CollectionUtils.isNotEmpty(list)) {
            renewalContract = list.get(0);
        } else {
            return contractRoomDO;
        }
        if (Objects.nonNull(renewalContract)) {
            Boolean firstOrderPayStatus = rentOrderService.getFirstOrderPayStatus(renewalContract.getId());
            if (firstOrderPayStatus){
                return getEndRenewalContract(renewalContract);
            }else {
                return contractRoomDO;
            }
        } else {
            return contractRoomDO;
        }
    }

    @Override
    public CommonResult<List<ContractRoomReqVO>> getContractByMemberId(Long memberId) {
        if (memberId == null) {
            return success(new ArrayList<>(0));
        }
        //查询企业入住、同住人，个人承租人的合同ID
        LambdaQueryWrapper<ContractRoommateDO> roommateWrapper = Wrappers.lambdaQuery();
        roommateWrapper.eq(ContractRoommateDO::getStatus, RoommateStatusEnum.CHECKED_ID.getCode())
                .eq(ContractRoommateDO::getMemberId, memberId)
                .and(s -> s.eq(ContractRoommateDO::getContractCustomerType, CustomerTypeEnum.COMPANY.getCode())
                        .or(k -> k.eq(ContractRoommateDO::getContractCustomerType, CustomerTypeEnum.PERSONAL)
                                .eq(ContractRoommateDO::getRoommateType, RoommateTypeEnum.LESSESS.getCode())));
        List<ContractRoommateDO> roommateList = this.contractRoommateMapper.selectList(roommateWrapper);
        if (CollectionUtils.isNotEmpty(roommateList)) {
            Set<Long> contractIds = roommateList.stream().map(s -> s.getRoomContractId()).collect(Collectors.toSet());
            LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(ContractRoomDO::getId, contractIds)
                    .in(ContractRoomDO::getContractStatus, Arrays.asList(ContractStatusEnum.CHECK_IN.getCode(),
                            ContractStatusEnum.ACTIVE.getCode()))
                    .orderByAsc(ContractRoomDO::getStartTime);
            List<ContractRoomDO> contractRoomDOS = contractRoomMapper.selectList(queryWrapper);
            return success(ContractConvert.INSTANCE.convertList07(contractRoomDOS));
        }
        return success(new ArrayList<>(0));
    }

    @Override
    public CommonResult<CompanyInfoVO> getCompanyCustomerById(Long id) {
        CustomerCompanyRespVO customerCompany = customerCompanyService.getCustomerCompany(id);
        return success(ContractConvert.INSTANCE.convert11(customerCompany));
    }

    @Override
    public CommonResult<ContractRoomRespVO> getContractRoomById(Long id) {
        if (Objects.nonNull(id)) {
            ContractRoomDO contractRoomDO = contractRoomService.get(id);
            if (Objects.nonNull(contractRoomDO)) {
                return success(ContractConvert.INSTANCE.convertDo2ContractRoomResp(contractRoomDO));
            }
        }
        return success(null);
    }

    /**
     * 用户查询当前代入住或已入住生效 合同房源信息
     *
     * @param memberIds
     */
    @Override
    public CommonResult<List<ContractRoomMemberUserVO>> getRoomNameByMemberIds(List<Long> memberIds) {
        if (CollectionUtil.isEmpty(memberIds)) {
            return success(new ArrayList<>());
        }
        return success(contractRoomMapper.getRoomNameByMemberIds(memberIds));
    }

    /**
     * 根据member_id查询入住时长
     *
     * @param memberId
     * @return
     */
    @Override
    public CommonResult<Long> getLengthOfStay(Long memberId) {
        List<ContractRoommateDO> contractRoommateDOS =
                contractRoommateMapper.selectList(new LambdaQueryWrapper<ContractRoommateDO>()
                        .eq(ContractRoommateDO::getMemberId, memberId)
                        .in(ContractRoommateDO::getStatus, RoommateStatusEnum.CHECKED_ID.getCode().toString(),
                                RoommateStatusEnum.RENTED.getCode().toString()));
        Long lengthOfStay = 0L;
        //存在入住记录
        if (CollectionUtil.isNotEmpty(contractRoommateDOS)) {
            //获取最小时间
            LocalDateTime localDateTime =
                    contractRoommateDOS.stream().map(ContractRoommateDO::getCreateTime).min(LocalDateTime::compareTo).get();
            LocalDate endDateTime = LocalDate.now();
            long count =
                    contractRoommateDOS.stream().filter(f -> RoommateStatusEnum.CHECKED_ID.getCode().toString().equals(f.getStatus())).count();

            //还未迁出
            if (count > 0) {
                lengthOfStay = (long) Period.between(localDateTime.toLocalDate(), endDateTime).getMonths();
            } else {
                //无未迁出的 查询历史
                Optional<LocalDate> max =
                        contractRoommateDOS.stream().filter(f -> ObjectUtil.isNotNull(f.getCheckoutTime()) || ObjectUtil.isNotNull(f.getUpdateTime())).map(m -> {
                            if (ObjectUtil.isNotNull(m.getCheckoutTime())) {
                                return m.getCheckoutTime();
                            } else {
                                return m.getUpdateTime().toLocalDate();
                            }
                        }).max(LocalDate::compareTo);
                //存在修改时间
                if (max.isPresent()) {
                    lengthOfStay = (long) Period.between(localDateTime.toLocalDate(), max.get()).getMonths();
                } else {
                    //数据异常但是存在入住以及迁出返回一个月
                    lengthOfStay = 1L;
                }
            }

        }
        return success(lengthOfStay);
    }

    /**
     * 根据member_id获取是否存在有效合同
     * true 为存在
     * false 不存在
     *
     * @param memberId
     * @return
     */
    @Override
    public CommonResult<Boolean> getPersonContractRoomStatus(Long memberId) {
        Long aLong = contractRoomMapper.selectCount(new LambdaQueryWrapper<ContractRoomDO>()
                .eq(ContractRoomDO::getMemberId, memberId)
                .eq(ContractRoomDO::getCustomerType, CustomerTypeEnum.PERSONAL.getCode())
                .in(ContractRoomDO::getContractStatus, ContractStatusEnum.ACTIVE.getCode(),
                        ContractStatusEnum.CHECK_IN.getCode())
        );
        return success(aLong > 0);
    }

    @Override
    public CommonResult<List<Long>> getActiveContractRooms(Long apartmentId) {
        LambdaQueryWrapper<ContractRoomDO> queryWrapper = new LambdaQueryWrapper<>();
        List<String> statusList = Arrays.asList(ContractStatusEnum.ACTIVE.getCode(), ContractStatusEnum.CHECK_IN.getCode());
        queryWrapper.in(ContractRoomDO::getContractStatus, statusList);
        queryWrapper.lt(ContractRoomDO::getStartTime,LocalDate.now());
        queryWrapper.eq(Objects.nonNull(apartmentId),ContractRoomDO::getApartmentId, apartmentId);
        List<ContractRoomDO> list = contractRoomMapper.selectList(queryWrapper);
        List<Long> roomIds = list.stream().map(ContractRoomDO::getRoomId).distinct().collect(Collectors.toList());
        return success(roomIds);
    }


    @Override
    @TenantIgnore
    public CommonResult<List<FeesApiVo>> getConfigFees(Long tenantId) {
        List<FeesApiVo> list = feesMapper.selectFeesList(tenantId);
        return success(list);
    }
}
